package com.xa.xamall.framework.service;

import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Repository;
import tk.mybatis.mapper.entity.Example;

import java.util.List;

/**
 * 泛型仓储接口
 * @param <T> 实体对象
 */
@Repository
public interface IBaseService<T> {

    /**
     * 根据实体中的属性值进行查询，查询条件使用等号
     * 接口：SelectMapper<T>
     * @param record 数据记录
     * @return List<T>
     */
    List<T> select(T record);

    /**
     * 根据主键字段进行查询，方法参数必须包含完整的主键属性，查询条件使用等号
     * 接口：SelectByPrimaryKeyMapper<T>
     * @param key 主键
     * @return T
     */
    T selectByPrimaryKey(Object key);

    /**
     * 查询全部结果，select(null)方法能达到同样的效果
     * 接口：SelectAllMapper<T>
     * @return List<T>
     */
    List<T> selectAll();

    /**
     * 查询分页结果
     * 接口：SelectAllMapper<T>
     * @param example 查询条件
     * @return List<T>
     */
    List<T> selectAll(Example example);

    /**
     * 查询分页结果
     * 接口：SelectAllMapper<T>
     * @param currPage 当前页码
     * @param pageSize 分页大小
     * @return List<T>
     */
    List<T> selectAll(int currPage, int pageSize);

    /**
     * 查询分页结果
     * 接口：SelectAllMapper<T>
     * @param example 查询条件
     * @param currPage 当前页码
     * @param pageSize 分页大小
     * @return List<T>
     */
    List<T> selectAll(Example example, int currPage, int pageSize);

    /**
     * 根据实体中的属性进行查询，只能有一个返回值，有多个结果则抛出异常，查询条件使用等号
     * 接口：SelectOneMapper<T>
     * @param record 数据记录
     * @return T
     */
    T selectOne(T record);

    /**
     * 根据属性进行查询，只能有一个返回值，有多个结果则抛出异常，查询条件使用等号
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return T
     */
    T selectOneByField(String fieldName, Object fieldValue);

    /**
     * 根据实体中的属性查询总数，查询条件使用等号
     * 接口：SelectCountMapper<T>
     * @param record 数据记录
     * @return 受影响的行数
     */
    int selectCount(T record);

    /**
     * 保存一个实体，null的属性也会保存，不会使用数据库默认值
     * 接口：InsertMapper<T>
     * @param record 数据记录
     * @return 受影响的行数
     */
    int insert(T record);

    /**
     * 保存一个实体，null的属性不会保存，会使用数据库默认值
     * 接口：InsertSelectiveMapper<T>
     * @param record 数据记录
     * @return 受影响的行数
     */
    int insertSelective(T record);

    /**
     * 根据主键更新实体全部字段，null值会被更新
     * 接口：UpdateByPrimaryKeyMapper<T>
     * @param record
     * @return 受影响的行数
     */
    int updateByPrimaryKey(T record);

    /**
     * 根据主键更新属性不为null的值
     * 接口：UpdateByPrimaryKeySelectiveMapper<T>
     * @param record 数据记录
     * @return 受影响的行数
     */
    int updateByPrimaryKeySelective(T record);

    /**
     * 根据实体属性作为条件进行删除，查询条件使用等号
     * 接口：DeleteMapper<T>
     * @param record 数据记录
     * @return 受影响的行数
     */
    int delete(T record);

    /**
     * 根据主键字段进行删除，方法参数必须包含完整的主键属性
     * 接口：DeleteByPrimaryKeyMapper<T>
     * @param key 主键
     * @return 受影响的行数
     */
    int deleteByPrimaryKey(Object key);

    /**
     * 根据Example条件进行查询
     * 这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列
     * 接口：SelectByExampleMapper<T>
     * @param example 查询示例
     * @return List<T>
     */
    List<T> selectByExample(Object example);

    /**
     * 根据指定字段查询
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return List<T>
     */
    List<T> selectByField(String fieldName, Object fieldValue);

    /**
     * 根据Example条件进行查询总数
     * 这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列
     * 接口：SelectCountByExampleMapper<T>
     * @param example 查询示例
     * @return 受影响的行数
     */
    int selectCountByExample(Object example);

    /**
     * 根据Example条件更新实体record包含的全部属性，null值会被更新
     * 这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列
     * 接口：UpdateByExampleMapper<T>
     * @param record 数据记录
     * @param example 查询示例
     * @return 受影响的行数
     */
    int updateByExample(T record, Object example);

    /**
     * 根据Example条件更新实体record包含的不是null的属性值
     * 这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列
     * 接口：UpdateByExampleSelectiveMapper<T>
     * @param record 数据记录
     * @param example 查询示例
     * @return 受影响的行数
     */
    int updateByExampleSelective(T record, Object example);

    /**
     * 根据Example条件删除数据
     * 这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列
     * 接口：DeleteByExampleMapper<T>
     * @param example 查询示例
     * @return 受影响的行数
     */
    int deleteByExample(Object example);

    /**
     * 根据Condition条件进行查询
     * 接口：SelectByConditionMapper<T>
     * @param condition 查询条件
     * @return List<T>
     */
    List<T> selectByCondition(Object condition);

    /**
     * 根据Condition条件进行查询总数
     * 接口：SelectCountByConditionMapper<T>
     * @param condition 查询条件
     * @return 受影响的行数
     */
    int selectCountByCondition(Object condition);

    /**
     * 根据Condition条件更新实体record包含的全部属性，null值会被更新
     * 接口：UpdateByConditionMapper<T>
     * @param record 数据记录
     * @param condition 查询条件
     * @return 受影响的行数
     */
    int updateByCondition(T record, Object condition);

    /**
     * 根据Condition条件更新实体record包含的不是null的属性值
     * 接口：UpdateByConditionSelectiveMapper<T>
     * @param record 数据记录
     * @param condition 查询条件
     * @return 受影响的行数
     */
    int updateByConditionSelective(T record, Object condition);

    /**
     * 根据Condition条件删除数据
     * 接口：DeleteByConditionMapper<T>
     * @param condition 查询条件
     * @return 受影响的行数
     */
    int deleteByCondition(Object condition);

    /**
     * 根据实体属性和RowBounds进行分页查询
     * 接口：SelectRowBoundsMapper<T>
     * @param record 数据记录
     * @param rowBounds 分页行界
     * @return List<T>
     */
    List<T> selectByRowBounds(T record, RowBounds rowBounds);

    /**
     * 根据example条件和RowBounds进行分页查询
     * 接口：SelectByExampleRowBoundsMapper<T>
     * @param example 查询示例
     * @param rowBounds 分页行界
     * @return List<T>
     */
    List<T> selectByExampleAndRowBounds(Object example, RowBounds rowBounds);

    /**
     * 根据example条件和RowBounds进行分页查询，该方法和selectByExampleAndRowBounds完全一样，只是名字改成了Condition
     * 接口：SelectByConditionRowBoundsMapper<T>
     * @param condition 查询条件
     * @param rowBounds 分页行界
     * @return List<T>
     */
    List<T> selectByConditionAndRowBounds(Object condition, RowBounds rowBounds);

    /**
     * 批量插入，支持批量插入的数据库可以使用，例如MySQL,H2等，另外该接口限制实体包含id属性并且必须为自增列
     * 接口：InsertListMapper<T>
     * @param recordList 记录集合
     * @return 受影响的行数
     */
    int insertList(List<T> recordList);

    /**
     * 插入数据，限制为实体包含id属性并且必须为自增列，实体配置的主键策略无效
     * 接口：InsertUseGeneratedKeysMapper<T>
     * @param record 数据记录
     * @return 受影响的行数
     */
    int insertUseGeneratedKeys(T record);

    /**
     * 根据主键字符串进行查询，类中只允许存在一个带有@Id注解的字段，否则会抛出异常。
     * 接口：SelectByIdsMapper
     * @param ids 通过操作ids字符串进行操作，ids 如 "1,2,3" 这种形式的字符串
     * @return List<T>
     */
    List<T> selectByIds(String ids);

    /**
     * 根据主键字符串进行删除，类中只允许存在一个带有@Id注解的字段，否则会抛出异常。
     * 接口：DeleteByIdsMapper
     * @param ids 通过操作ids字符串进行操作，ids 如 "1,2,3" 这种形式的字符串
     * @return 受影响的行数
     */
    int deleteByIds(String ids);

    /**
     * 单表分页查询
     * @param pageNum 当前页码
     * @param pageSize 分页大小
     * @return List<T>
     */
    List<T> pageList(int pageNum, int pageSize);

    /**
     * 验证数据是否存在
     * 接口：SelectByExampleMapper<T>
     * @param example 查询示例
     * @return boolean
     */
    boolean existByExample(Object example);

    /*#########################################################################*/
    /*                           自定义扩展接口                                */
    /*#########################################################################*/

    /**
     * 查询某个字段值是否存在
     * @param record 查询实体条件
     * @return boolean
     */
    boolean exist(T record);
}
